<?php
/**
 * 商品搜索 对Es搜索引擎的一些操作
 */

use app\library\facade\Db;
use app\library\facade\Redis;
use app\library\redis\RedisKey;
use app\library\facade\Es;
use app\business\EsBusiness;
use app\library\facade\Config;

/**
 * Class EsController
 */
class EsController extends BaseController
{
    /**
     * 默认初始化方法，如果不需要，可以删除掉这个方法
     * 如果这个方法被定义，那么在Controller被构造以后，Yaf会调用这个方法
     */
    public function init()
    {
    }

    /**
     * 默认动作
     * Yaf支持直接把\Yaf\Request_Abstract::getParam()得到的同名参数作为Action的形参
     * 对于如下的例子, 当访问http://yourhost/demo/index/index/index/name/root 的时候, 你就会发现不同
     */

    /**
     * 数据同步
     */
    public function goodsImportAction()
    {
        (new EsBusiness())->createIndex();
        //获取上次导入的后的最大的common_id;
        $redis_key = RedisKey::getEsLastIdKey();
        $last_id = Redis::exists($redis_key);
        if ($last_id) {
            $last_id = Redis::get($redis_key);
        }
        $list = Db::select('yf_goods_common', ['common_id', 'common_name', 'common_spec_value'], [
            'shop_id' => 3,
            'is_del' => 1,
            'common_state' => 1,
            "common_id[>]" => $last_id,
            'LIMIT' => 20
        ]);

        if ($list) {
            $list_new = [];
            array_map(function($item) use (&$list_new) {
                $name = $item['common_name'];
                if (!empty($item['common_spec_value'])) {
                    $item['common_spec_value'] = json_decode($item['common_spec_value'], true);
                    if (!empty($item['common_spec_value'])) {
                        foreach ($item['common_spec_value'] as $spec) {
                            $name .= array_shift($spec);
                        }
                    }
                }
                $list_new[] = [
                    'common_id' => $item['common_id'],
                    'common_name' => $name,
                ];
            }, $list);
            //开始数据导入
            foreach ($list_new as $item) {
                try {
                    $res = @Es::index([
                        'index' => Config::get('es.index'),
                        'id' => $item['common_id'],
                        'body' => [
                            'common_id' => $item['common_id'],
                            'common_name' => $item['common_name']
                        ]
                    ]);
                } catch (Exception $e) {
                    return $this->returnError(1, $e->getMessage());
                }
            }
            //保存本次最大的commin_id
            Redis::set(RedisKey::getEsLastIdKey(), array_pop($list)['common_id']);
        }
        return $this->returnSuccess();
    }

    /**
     * 搜索
     */
    public function searchGoodsAction()
    {
        $request = $this->getRequest();
        if (!$request->isGet()) {
            return $this->returnError(1, 'error');
        }
        $search_text = htmlspecialchars($request->getQuery("search_text"));
        $page = intval($request->getQuery("page"));
        $pagesize = intval($request->getQuery('pagesize'));
        if (empty($search_text)) {
            return $this->returnError(10001, '缺少参数search_text');
        }
        if (empty($page)) {
            return $this->returnError(10001, '缺少参数page');
        }
        if (empty($pagesize)) {
            return $this->returnError(10001, '缺少参数pagesize');
        }
        $res = @Es::search([
            'index' => Config::get('es.index'),
            'body' => [
                'query' => [
                    'bool' => [
                        'must' => [
                            ['match' => ['common_name' => $search_text]],
                        ],
                    ],
                ],
                'from' => ($page - 1) * $pagesize,
                'size' => $pagesize
            ]
        ]);
        if (isset($res['hits']['hits']) && count($res['hits']['hits']) > 0) {
            $arr = array_map(function($item) {
                return $item['_id'];
            }, $res['hits']['hits']);
            return $this->returnSuccess(['common_ids' => $arr, 'list' => $res['hits']['hits']]);
        } else {
            return $this->returnError(10002, '没有更多的数据');
        }
    }

    /**
     * 商品数据更新策略
     * 方案1:定时全部删除,然后从新添加
     * 方案2:逐一进行比较,每10分钟执行一次,取出mysql跟es的数据进行比对,不存在侧添加,不同则更新,下架则删除,相同则不操作
     */
    public function updateGoodsAction()
    {
        //获取最大的common_ic
        if (Redis::exists(RedisKey::getEsLastIdKey())) {
            $last_id = Redis::get(RedisKey::getEsLastIdKey());
        } else {
            return $this->returnError(2, 'error');
        }
        //获取当前的游标
        if (Redis::exists(RedisKey::getEsGoodsVernier())) {
            $vernier = Redis::get(RedisKey::getEsGoodsVernier());
        } else {
            $vernier = 0;
        }
        //如果当前游标 大于等于 当前的common_id 重置游标
        if ($vernier >= $last_id) {
            $vernier = 0;
        }

        $goods = Db::get('yf_goods_common', '*', [
            'shop_id' => 3,
            'common_state' => 1,
            "common_id[>]" => $vernier,
        ]);
        $name = '';
        if (!empty($goods['common_spec_value'])) {
            $goods['common_spec_value'] = json_decode($goods['common_spec_value'], true);
            if (!empty($goods['common_spec_value'])) {
                foreach ($goods['common_spec_value'] as $spec) {
                    $name .= array_shift($spec);
                }
            }
        }
        $name = $goods['common_name'] . $name;

        $es_index = Config::get('es.index');
        $es = @Es::get([
            'index' => $es_index,
            'id' => $goods['common_id']
        ]);

        if (!empty($es['_source'])) {
            if ($goods['is_del'] == 1) {
                //判断是否更新
                if ($es['_source']['common_name'] != $name) {
                    //更新
                    @Es::update([
                        'index' => $es_index,
                        'id' => $goods['common_id'],
                        'body' => [
                            'doc' => [
                                'common_name' => $name
                            ]
                        ]
                    ]);
                }
            } else {
                //删除
                @Es::delete([
                    'index' => $es_index,
                    'id' => $goods['common_id']
                ]);
            }
        } else {
            if ($goods['is_del'] == 1) {
                //添加
                @Es::index([
                    'index' => $es_index,
                    'id' => $goods['common_id'],
                    'body' => [
                        'common_id' => $goods['common_id'],
                        'common_name' => $name
                    ]
                ]);
            }
        }

        Redis::set(RedisKey::getEsGoodsVernier(), $goods['common_id']);

        return $this->returnSuccess();
    }

    /**
     * 创建索引
     */
    public function createIndexAction()
    {
        $indices = Es::indices();

        $es_index = Config::get('es.index');
        //判断索引是否存在
        $res = $indices->exists(['index' => $es_index]);
        if (!$res) {
            //如果不存在则创建
            $res = @$indices->create([
                'index' => $es_index,
                'body' => [
                    'settings' => [//配置
                        'number_of_shards' => 3,//主分片数
                        'number_of_replicas' => 2, //主分片的副本数
                        'index.max_ngram_diff' => 5,
                        'analysis' => [
                            'filter' => [
                                'ngram_filter' => [
                                    'type' => 'ngram',
                                    'min_gram' => 2,
                                    'max_gram' => 6
                                ]
                            ],
                            'analyzer' => [
                                'ngram_analyzer' => [
                                    'type' => "custom",
                                    'tokenizer' => "whitespace",
                                    'filter' => [
                                        'lowercase',
                                        'ngram_filter'
                                    ]
                                ]
                            ]
                        ]
                    ],
                    'mappings' => [
//                        'goods' => [
                            '_source' => [
                                'enabled' => true
                            ],
                            'properties' => [
                                'common_id' => [
                                    'type' => 'integer'
                                ],
                                'common_name' => [
                                    'type' => 'text',
                                    'analyzer' => 'ik_max_word',
                                    'search_analyzer' => 'ik_max_word',
                                ]
                            ]
//                        ]
                    ]
                ]
            ]);
            return $this->returnSuccess();
        } else {
            return $this->returnError(10012, '已创建');
        }
    }

}
